package sg.edu.nus.iss.cerberus.wizard;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import sg.edu.nus.iss.cerberus.engine.JUnitMethodCheck;
import sg.edu.nus.iss.cerberus.extensionpoint.INewTestCaseWizardPage;
import sg.edu.nus.iss.cerberus.extensionpoint.NewTestCaseWizardPagePosition;
import sg.edu.nus.iss.cerberus.model.CClass;
import sg.edu.nus.iss.cerberus.model.CMemberMethod;
import sg.edu.nus.iss.cerberus.model.MethodTestData;
import sg.edu.nus.iss.cerberus.model.TestGenerationData;
import sg.edu.nus.iss.cerberus.util.CerberusConstants;

public class MethodTestDataPage extends WizardPage implements
		INewTestCaseWizardPage {

	private Label[] lbl;
	private CCombo[] combo;
	private Text[][] txtBox;
	private CMemberMethod[] methodNames;
	private int maxNumberOfParams;

	private IWizardPage wizardpage;
	private TestGenerationData testGenData;
	private String pageId = CerberusConstants.WIZARD_EDITOR_TITLE;

	protected MethodTestDataPage(String pageName, TestGenerationData testGenData) {
		super(pageName);
		this.wizardpage = this;
		this.setTitle(pageId);
		this.testGenData = testGenData;
		this.methodNames = methodInCUT(testGenData.getCut());
		this.maxNumberOfParams = getMaxNumberOfParams(this.methodNames);
		lbl = new Label[methodNames.length];
		combo = new CCombo[methodNames.length];
		txtBox = new Text[methodNames.length][maxNumberOfParams + 3];
	}

	@Override
	public void createControl(Composite parent) {
		final ScrolledComposite sc1 = new ScrolledComposite(parent, SWT.H_SCROLL|SWT.V_SCROLL|SWT.BORDER);
		sc1.setExpandHorizontal(true);
		sc1.setExpandVertical(true);
		final Composite c1 = new Composite(sc1, SWT.NONE);
		sc1.setContent(c1);
		GridLayout layout = new GridLayout(maxNumberOfParams + 3,false);
		layout.verticalSpacing = 15;
		layout.horizontalSpacing=10;
		layout.marginTop = 20;
		c1.setLayout(layout);
		
		setControl(c1);
		
		for (int i = 0; i < methodNames.length; i++) {

			for (int j = 0; j < maxNumberOfParams + 3; j++) {
				if (j == 0) {
					lbl[i] = new Label(c1, SWT.NONE);
					lbl[i].setText(methodNames[i].getFullSignature());
					lbl[i].setToolTipText("Method Under Test");
				} else if (j == 1) {
					combo[i] = new CCombo(c1, SWT.DROP_DOWN
							| SWT.READ_ONLY);
					combo[i].setText("Select Asserts");
					combo[i].setSize(70, 30);
					combo[i].setBackground(new Color(Display.getCurrent(), 255,
							255, 255));
					combo[i].setItems(CerberusConstants.assertList);
					combo[i].setToolTipText("Select Asserts");
				} else {
					txtBox[i][j] = new Text(c1, SWT.NONE);
					txtBox[i][j].setEditable(false);
					if(j == 2)
						txtBox[i][j].setToolTipText("Expected Value");
				}
			}
		}

		for (int i = 0; i < methodNames.length; i++) {
			for (int j = 2; j <= makeTextNonEditable(methodNames[i],
					lbl[i].getText()); j++) {
					txtBox[i][j].setEditable(true);
					if( j > 2 )
					txtBox[i][j].setToolTipText("Arguments vlaue");
			}
		}
		sc1.setMinSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));

	}

	private ArrayList<MethodTestData> readData() {
		ArrayList<MethodTestData> testData = new ArrayList<MethodTestData>();
		for (int i = 0; i < methodNames.length; i++) {
			ArrayList<String> params = new ArrayList<String>();
			MethodTestData mtData = new MethodTestData();
			for (int j = 0; j < maxNumberOfParams + 3; j++) {

				if (j == 0) {
					mtData.setSignature(lbl[i].getText().trim());
					mtData.setName(methodNames[i].getMethodName());
				} else if (j == 1) {
					if (combo[i].getSelectionIndex() != -1) {
						ArrayList<String> asserts = new ArrayList<String>();
						asserts.add(CerberusConstants.assertList[combo[i]
								.getSelectionIndex()]);
						JUnitMethodCheck jUnitCheck = new JUnitMethodCheck(
								asserts);
						mtData.setAssertCheck(jUnitCheck);
					}
				} else if (j == 2) {
					if(txtBox[i][j].getText().trim().isEmpty())
						mtData.setExpected("");
					else					
					mtData.setExpected(txtBox[i][j].getText().trim());
					
				} 
				else {
					if (!txtBox[i][j].getText().trim().isEmpty())
						params.add(txtBox[i][j].getText().trim());
					else
						params.add("");
				}

			}

			mtData.setParam(params);
			testData.add(mtData);
		}
		return testData;
	}

	@Override
	public String getId() {
		return this.pageId;
	}

	@Override
	public IWizardPage getPage() {
		return this.wizardpage;
	}

	@Override
	public NewTestCaseWizardPagePosition getPosition() {
		NewTestCaseWizardPagePosition position = NewTestCaseWizardPagePosition
				.before(this.pageId);
		return position;
	}

	public TestGenerationData updateTestGenData() {
		this.testGenData.setMethodTestData(readData());
		return this.testGenData;
	}

	private CMemberMethod[] methodInCUT(CClass cut) {
		HashMap<String, ArrayList<CMemberMethod>> hashMethods = cut
				.getMethodHash();
		ArrayList<ArrayList<CMemberMethod>> cMemberMethod = new ArrayList<ArrayList<CMemberMethod>>(
				hashMethods.values());
		Iterator<ArrayList<CMemberMethod>> iter = cMemberMethod.iterator();
		ArrayList<CMemberMethod> methodNames = new ArrayList<CMemberMethod>();
		while (iter.hasNext()) {
			ArrayList<CMemberMethod> cMethod = iter.next();
			Iterator<CMemberMethod> iterCMethod = cMethod.iterator();
			while (iterCMethod.hasNext()) {
				CMemberMethod cMethodName = iterCMethod.next();
				methodNames.add(cMethodName);
			}
		}
		CMemberMethod[] objCMethod = new CMemberMethod[methodNames.size()];

		for (int i = 0; i < objCMethod.length; i++) {
			objCMethod[i] = methodNames.get(i);
		}

		return objCMethod;
	}

	private int getMaxNumberOfParams(CMemberMethod[] methodNames) {
		int tmp = 0;
		int store = 0;
		for (int z = 0; z < methodNames.length; z++) {
			tmp = methodNames[z].getParametersCount();
			if (tmp > store) {
				store = tmp;
			}
		}
		return store;
	}

	private int makeTextNonEditable(CMemberMethod row, String methodSignature) {
		int noOfColumns = 0;
		if (methodSignature.equalsIgnoreCase(row.getFullSignature())
				&& (row.getParams() != null)) {
			noOfColumns = row.getParams().size();
		}
		// Text boxes excluding First and second column
		return noOfColumns + 2;
	}
}
